package com.study.kt._03coroutines

import kotlinx.coroutines.*
import java.lang.Runnable
import kotlin.concurrent.thread

/**
 *
 *
 *
 * 协程的启动：上下文、启动模式、协程体，协程体
 */
fun main1() {
    // startAndDelay()
    // coroutineBuilder()
    // startDefault()
    // startLazy()
    // startAtomic()
}

// 获取协程返回值，Job获取不到返回值，但是可以操作生命周期
fun main2() = runBlocking {
    val job = GlobalScope.launch {
        delay(1000)
        println("return job")
    }
    println("hello")
    // 挂起协程，直到协程结束,输出:hello->return job->world
    // 此处使用 GlobalScope.启动协程类似于守护线程，主线程运行结束，守护线程也结束了
    // 如果此处不使用join，则主线程运行结束后，协程也会停止，delay后面的就不会执行
    job.join()
    println("world")
}

// 每个协程构建器(包括runBlocking)都会向其代码块作用域中添加一个GoroutineScope实例（使用哪个协程构造器就是哪个GoroutineScope 协程作用域）
// 可以在该作用域启动协程，不需要显示使用job讲其内部协程和外部协程添加到一起
// 例如下面的示例：直接launch，内部运行结束才算程序结束,而且外部协程需要等待内部协程运行结束才运行
// 如果使用GlobalScope.launch 而且不使用join，则runBlocking执行结束程序停止，内部的协程也停止运行
fun main() = runBlocking {
    /*GlobalScope.*/
    launch {
        delay(1000)
        println("launch")
    }
    println("hello")
}

// 协程运行机制
fun startAndDelay() {
    GlobalScope.launch {
        delay(1000)
        println("coroutines launch")
    }
    println("hello")
    /* 此处休眠两秒 协程会执行hello coroutines launch world
        如果此处休眠500毫秒，则coroutines launch不会打印，因为线程运行结束，依附于线程的协程也退出了
    * */
    Thread.sleep(2000)
    println("world")
}

// 使用线程模拟上述机制
fun byThread() {
    thread {
        Thread.sleep(1000)
        println("thread run")
    }
    println("hello")
    Thread.sleep(2000)
    println("world")
}

// 协程构建器
fun coroutineBuilder() {
    // 1.在后台创建一个新的协程并立即执行协程代码，并且不会阻塞当前线程
    GlobalScope.launch {
        println("1.GlobalScope.launch")
    }

    // 2.创建一个协程，并阻塞当前线程
    runBlocking {
        delay(1000)
        println("2.runBlocking")
    }

    println("0.main")
}

// 启动模式：DEFAULT
// DEFAULT 是饿汉式启动，launch 调用后，会立即进入待调度状态，一旦调度器 OK 就可以开始执行
// 根据CPU对后台、当前线程调度输出结果可能为1 2 3 4，也可能是1 3 2 4
suspend fun startDefault() {
    println("1")
    val job = GlobalScope.launch {
        // 挂起函数
        println("2")
    }
    println("3")
    job.join()
    println("4")
}

//LAZY 是懒汉式启动，launch 后并不会有任何调度行为，协程体也自然不会进入执行状态，直到我们需要它执行的时候
suspend fun startLazy() {
    println("1")
    val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
        println("2")
    }
    println("3")
    job.start()
    println("4")
}

// 立即执行协程体，但在开始运行之前无法取消
@ExperimentalCoroutinesApi
suspend fun startAtomic() {
    println("1")
    val job = GlobalScope.launch(start = CoroutineStart.ATOMIC) {
        println("2")
    }
    // 使用cancel后，协程一定会被调度
    job.cancel()
    println("3")
}

// 立即在当前线程执行协程体，直到第一个 suspend 调用
suspend fun startUndispatched() {
    println("1")
    val job = GlobalScope.launch(start = CoroutineStart.UNDISPATCHED) {
        println("2")
    }
    // 使用cancel后，协程一定会被调度
    job.cancel()
    println("3")
}